#!/usr/bin/python

# nwgr: new way of grepping stuff
#
#Copyright (C) 2007-2009 Thiago Galesi
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; either version 2
#of the License, or (at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#

import sys, re, getopt, fileinput, os, stat, linecache, profile

# grep substitute
# features:
# egrep behavior
# new options

lox = dict()
lox['cf'] = '\.((c((pp)|c)?)|(h(h)?))$'
lox['ch'] = '\.(h(h)?)$'
lox['cs'] = '\.((c((pp)|c?)))?$'
lox['py'] = '\.py$'

def usage():
	print """
tbgr: A new option for grepping stuff
v 0.2
options:
-r recurse subdirectories
-f files to grep
-v prints line number for vi opening
-e regex to look for
--frgx regex to determine which files to print
--fx indicates regex mnemonic to use
-n prints line number information
-s simplified file name printing: file.txt instead of...
/somewhere/over/the/rainbow/file.txt
-w does not print file name at beginning of path
-y does not print spaces/tabs before the line
but instead once before any matching lines
"""
	print "--fx choices"
	for i in lox.keys():
		print "%s - %s"%(i, lox[i])
	print
	sys.exit(2)

def walktree(top, recurse):
	#print top
	file_list = []
	islist = False
	for f in top:
		try:
			mode = os.stat(f)[stat.ST_MODE]
		except:
			continue
		if stat.S_ISDIR(mode) and not stat.S_ISLNK(mode):
			# It's a directory, recurse into it
			#print str(f)+'is a directory'
			# not going round the tail
			lstd = os.listdir(f)
			fls = []
			drl = []
			for i in lstd:
				fulp = os.path.join(f, i)
				if stat.S_ISDIR(os.stat(fulp)[stat.ST_MODE]):
					drl.append(fulp)
				else:
					fls.append(fulp)
			if (recurse==True):
				file_list += walktree(drl, True)
			file_list += fls
		elif stat.S_ISREG(mode):
			file_list.append(f)
	return file_list

def spath(nrm):
	vl = nrm.rfind('/')
	if vl!=(-1):
		return nrm[vl+1:]
	assert(0)

def intr_line_asm(file_list, comp_regx):
	ill = []
	for fname in file_list:
		try:
			for line in fileinput.input(fname):
				if (comp_regx.search(line)!=None):
					ill.append((fname,
						fileinput.filelineno(), line[:-1]))
		except IOError:
			sys.stderr.write("Error opening file %s \n"%(fname))
		except KeyboardInterrupt:
			sys.exit(1)
		except:
			sys.stderr.write("This should not have happened")

	return ill

# list of opts
# lnn - prints line number
# shp - prints short path
# vi  - prints path + line number in vi copy paste format
# jof - prints file name just once


def il_print(ill, opt_l):
	lineno = False
	shp = False
	jof = False
	vio = False
	sks = False
	if 'lnn' in opt_l:
		lineno = True
	if 'shp' in opt_l:
		shp = True
	if 'jof' in opt_l:
		jof = True
	if 'vi' in opt_l:
		vio = True
	if 'sks' in opt_l:
		sks = True

	lfn = "/"
	for le in ill:
		linenotxt = ""
		prld = ""
		if (lineno):
			if (vio):
				linenotxt += " +%d "%(le[1])
			else:
				linenotxt += ":%d "%(le[1])
		else:
			linenotxt += ":"
		if (jof):
			if (le[0] != lfn):
				lfn = le[0]
				if (shp):
					print "<%s>"%(spath(lfn))
				else:
					print "<%s>"%(lfn)
		else:
			if (shp):
				prld += spath(le[0])
			else:
				prld += le[0]
		ltxt = le[2]
		if (sks):
			ltxt = ltxt.lstrip()
		prld += linenotxt
		print "%s %s"%(prld, ltxt)

def tk2frgx(opt):
	try:
		rt = lox[opt]
	except:
		print 'Invalid regex set choice\n'
		sys.exit(5)
	return rt

def main():
	#print sys.argv[1:]
	try:
		opcs, args = getopt.gnu_getopt(sys.argv[1:], 'rf:e:c:nswvy',['frgx=', 'short_path', 'fx='])
	except getopt.GetoptError:
                usage()
	#print opcs
	o_recurse = False
	o_lineno = False
	o_regex = ''
	o_files = ''
	o_contxt = ''
	o_frgx = ''
	o_nwfi = False
	o_shortpath = False
	fpol = []
	for op, vl in opcs:
		if op in ['-s','--short_path']:
			o_shortpath = True
			fpol.append('shp')
		if op == '-r':
			o_recurse = True
		if op == '-f':
			o_files = vl
		if op == '-e':
			o_regex = vl
		if op == '-w':
			o_nwfi = True
			fpol.append('jof')
		if op == '-v':
			fpol.append('vi')
			fpol.append('lnn')
			o_lineno = True
		if op == '-y':
			fpol.append('sks')
		if op == '-c':
			o_contxt = vl
		if op == '--frgx':
			o_frgx = vl
		if op == '-n':
			o_lineno = True
			fpol.append('lnn')
		if op == '--fx':
			o_frgx = tk2frgx(vl)

	if (o_regex==''): usage()
	#if ((o_files=='') & (len(args)==0)): usage()
	try:
		crgx = re.compile(o_regex)
	except:
		print 'faulty regular expression'
		sys.exit(3)
	#print o_files
	if (type(o_files)==str):
		o_files = [o_files]
	o_files += args
	if (len(o_files) == 1 and o_files[0] == ''):
		o_files = ['.']
	if (o_recurse == False):
		o_files = walktree(o_files, False)
	else:
		o_files = walktree(o_files, True)
	if (len(o_files)==0):
		sys.exit(0)
	if (o_frgx!=''):
		try:
			frgx = re.compile(o_frgx)
		except:
			print 'faulty file regular expression'
			sys.exit(3)
		oof = []
		for fl in o_files:
			if (frgx.search(fl)!=None):
				oof.append(fl)
		o_files = oof
		#print 'oof = ' +str(oof)
	#comp_grep(o_files, crgx, o_contxt, o_nwfi, o_shortpath, o_lineno)
	for fl in o_files:
		ill = intr_line_asm([fl], crgx)
		if (len(ill) == 0):
			continue
		il_print(ill, fpol)

if __name__=='__main__':
	#profile.run('main()')
	main()

